package com.sky.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.mybatis.mp.core.mybatis.mapper.context.Pager;
import cn.mybatis.mp.core.sql.executor.chain.QueryChain;
import com.github.pagehelper.Page;
import com.sky.constant.MessageConstant;
import com.sky.constant.RedisKeyConstant;
import com.sky.constant.UserStatusConstant;
import com.sky.dto.UserBanDTO;
import com.sky.dto.UserPageQueryDTO;
import com.sky.dto.UserStatusDTO;
import com.sky.entity.Admins;
import com.sky.entity.UserBans;
import com.sky.entity.Users;
import com.sky.exception.BaseException;
import com.sky.mapper.UserBansMapper;
import com.sky.mapper.UsersMapper;
import com.sky.service.AdminUserService;
import com.sky.service.UserBanService;
import com.sky.vo.UserBanInfoVO;
import com.sky.vo.UserPageVO;
import db.sql.api.cmd.GetterFields;
import db.sql.api.impl.cmd.basic.OrderByDirection;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户封禁服务实现类
 * 提供用户封禁相关的功能，包括：
 * - 用户封禁和解封
 * - 封禁状态查询
 * - 封禁历史记录管理
 * - 封禁时长计算
 */
@Service
@Slf4j
public class UserBanServiceImpl implements UserBanService {

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private UserBansMapper userBansMapper;

    @Autowired
    private AdminUserService adminUserService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 将用户添加到临时封禁列表
     * @param userId 用户ID
     */
    private void addUserToTempBanList(Integer userId) {
        redisTemplate.opsForList().rightPush(RedisKeyConstant.TEMP_BANNED_USERS_LIST, userId.toString());
    }

    /**
     * 从临时封禁列表中移除用户
     * @param userId 用户ID
     */
    private void removeUserFromTempBanList(Integer userId) {
        redisTemplate.opsForList().remove(RedisKeyConstant.TEMP_BANNED_USERS_LIST, 0, userId.toString());
    }

    /**
     * 更新用户封禁状态
     * <p>
     * 功能：
     * 1. 封禁/解封用户
     * 2. 记录封禁历史
     * 3. 使用Sa-Token进行权限控制
     * <p>
     * 安全检查：
     * - 验证用户存在性
     * - 防止管理员被封禁
     * - 验证封禁原因和时长
     * - 检查重复封禁
     *
     * @param userId 用户ID
     * @param banDTO 封禁信息传输对象，包含：
     *               - status: 目标状态（0-正常，1-封禁）
     *               - reason: 封禁原因
     *               - banDuration: 封禁时长（小时）
     * @throws BaseException 当封禁操作不合法时抛出异常
     */
    @Override
    @Transactional
    public void updateUserStatus(Integer userId, UserBanDTO banDTO) {
        // 1. 检查用户是否存在
        Users user = usersMapper.get(where -> where.eq(Users::getUserId, userId));
        if (user == null) {
            throw new BaseException(MessageConstant.USER_NOT_FOUND);
        }

        if (banDTO.getStatus() != UserStatusConstant.NORMAL && banDTO.getStatus() != UserStatusConstant.BANNED) {
            throw new BaseException(MessageConstant.INVALID_STATUS);
        }

        if (banDTO.getStatus() == UserStatusConstant.BANNED) {
            if (!StringUtils.hasText(banDTO.getReason())) {
                throw new BaseException(MessageConstant.BAN_REASON_REQUIRED);
            }
            if (banDTO.getBanDuration() != null && banDTO.getBanDuration() <= 0) {
                throw new BaseException(MessageConstant.BAN_DURATION_INVALID);
            }
            if (user.getStatus() == UserStatusConstant.BANNED) {
                throw new BaseException(MessageConstant.USER_ALREADY_BANNED);
            }
        } else if (user.getStatus() != UserStatusConstant.BANNED) {
            throw new BaseException(MessageConstant.USER_NOT_BANNED);
        }

        // 更新用户状态
        user.setStatus(banDTO.getStatus());
        usersMapper.update(user);

        if (banDTO.getStatus() == UserStatusConstant.BANNED) {
            // 使用Sa-Token进行封禁
            if (banDTO.getBanDuration() != null && banDTO.getBanDuration() > 0) {
                //先踢下线
                StpUtil.kickout(userId);
                //封禁
                StpUtil.disable(userId, banDTO.getBanDuration());
                // 添加到临时封禁列表（只有临时封禁的用户才添加到列表）
                addUserToTempBanList(userId);
            } else {
                //先踢下线
                StpUtil.kickout(userId);
                //封禁，永封
                StpUtil.disable(userId, -1);
                // 永久封禁的用户不添加到临时封禁列表
            }

            // 记录封禁历史
            UserBans banRecord = new UserBans();
            banRecord.setUserId(userId);
            banRecord.setBanTime(new Date());
            banRecord.setBanDuration(banDTO.getBanDuration());
            banRecord.setBanReason(banDTO.getReason());
            banRecord.setAdminId(StpUtil.getLoginIdAsInt());

            userBansMapper.save(banRecord);
        } else {
            // 解除封禁
            StpUtil.untieDisable(userId);
            // 从临时封禁列表中移除
            removeUserFromTempBanList(userId);
        }
    }

    /**
     * 获取用户封禁状态
     * <p>
     * 功能：
     * 1. 获取用户当前封禁状态
     * 2. 计算剩余封禁时长
     * 3. 获取封禁原因和详情
     *
     * @param userId 用户ID
     * @return UserStatusDTO 用户状态传输对象，包含：
     * - userId: 用户ID
     * - status: 当前状态
     * - reason: 封禁原因
     * - banDuration: 封禁时长
     * - banEndTime: 预计解封时间
     * @throws BaseException 当用户不存在时抛出异常
     */
    @Override
    public UserStatusDTO getUserBanStatus(Integer userId) {
        Users user = QueryChain.of(usersMapper)
                .select(Users.class)
                .eq(Users::getUserId, userId)
                .get();

        if (user == null) {
            throw new BaseException(MessageConstant.USER_NOT_FOUND);
        }

        UserStatusDTO statusDTO = new UserStatusDTO();
        statusDTO.setUserId(userId);
        statusDTO.setStatus(user.getStatus());

        if (StpUtil.isDisable(userId)) {
            long disableTime = StpUtil.getDisableTime(userId);
            UserBans currentBan = getCurrentBan(userId);

            if (currentBan != null) {
                statusDTO.setReason(currentBan.getBanReason());
                statusDTO.setBanDuration(currentBan.getBanDuration());
            }

            if (disableTime > 0) {
                statusDTO.setBanDuration((int) (disableTime / 3600));
                statusDTO.setBanEndTime(LocalDateTime.now().plusSeconds(disableTime));
            }
        }

        return statusDTO;
    }

    /**
     * 获取用户封禁历史记录
     * <p>
     * 功能：
     * 1. 验证用户存在性
     * 2. 获取所有封禁记录
     * 3. 按时间降序排序
     *
     * @param userId 用户ID
     * @return List<UserBans> 封禁历史记录列表，每条记录包含：
     * - banTime: 封禁时间
     * - banDuration: 封禁时长
     * - banReason: 封禁原因
     * - adminId: 操作管理员ID
     * @throws BaseException 当用户不存在时抛出异常
     */
    @Override
    public List<UserBans> getUserBanHistory(Integer userId) {
        Users user = QueryChain.of(usersMapper)
                .select(Users.class)
                .eq(Users::getUserId, userId)
                .get();

        if (user == null) {
            throw new BaseException(MessageConstant.USER_NOT_FOUND);
        }

        return QueryChain.of(userBansMapper)
                .select(UserBans.class)
                .eq(UserBans::getUserId, userId)
                .orderBy(UserBans::getBanTime)
                .list();
    }

    /**
     * 获取用户当前封禁信息
     * <p>
     * 功能：
     * 1. 检查用户是否处于封禁状态
     * 2. 获取最新的封禁记录
     * 3. 计算剩余封禁时长
     *
     * @param userId 用户ID
     * @return UserBanInfoVO 封禁信息视图对象，包含：
     * - banDuration: 封禁时长
     * - banTimeLeft: 剩余时长
     * - banAdminName: 操作管理员
     * - banReason: 封禁原因
     * - banTime: 封禁时间
     * - status: 状态
     * @return null 如果用户未被封禁或不存在
     */
    @Override
    public UserBanInfoVO getCurrentBanInfo(Integer userId) {
        // 检查用户当前是否处于封禁状态
        Users user = QueryChain.of(usersMapper)
                .select(Users.class)
                .eq(Users::getUserId, userId)
                .get();

        if (user == null || user.getStatus() != UserStatusConstant.BANNED) {
            return null;
        }

        UserBans currentBan = QueryChain.of(userBansMapper)
                .select(UserBans.class)
                .eq(UserBans::getUserId, userId)
                .orderBy(UserBans::getBanTime)
                .limit(1)
                .get();

        if (currentBan == null) {
            return null;
        }

        UserBanInfoVO banInfoVO = new UserBanInfoVO();
        Admins admins = adminUserService.getAdminDetails(currentBan.getAdminId());
        BeanUtils.copyProperties(currentBan, banInfoVO);
        banInfoVO.setBanAdminName(admins.getUsername());

        // 计算剩余封禁时长
        if (currentBan.getBanDuration() != null) {
            LocalDateTime endTime = currentBan.getBanTime().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime()
                    .plusHours(currentBan.getBanDuration());
            if (LocalDateTime.now().isBefore(endTime)) {
                long hoursLeft = ChronoUnit.HOURS.between(LocalDateTime.now(), endTime);
                banInfoVO.setBanTimeLeft((int) hoursLeft);
            }
        }

        return banInfoVO;
    }

    /**
     * 检查用户是否被封禁
     * <p>
     * 功能：
     * 1. 查询用户状态
     * 2. 判断是否处于封禁状态
     *
     * @param userId 用户ID
     * @return boolean true-已封禁，false-未封禁或用户不存在
     */
    @Override
    public boolean isUserBanned(Integer userId) {
        Users user = QueryChain.of(usersMapper)
                .select(Users.class)
                .eq(Users::getUserId, userId)
                .get();
        return user != null && user.getStatus() == UserStatusConstant.BANNED;
    }

    /**
     * 获取用户最新的封禁记录
     * <p>
     * 功能：
     * 1. 查询最新一条封禁记录
     * 2. 按封禁时间降序排序
     *
     * @param userId 用户ID
     * @return UserBans 封禁记录实体，包含完整的封禁信息
     */
    private UserBans getCurrentBan(Integer userId) {
        return QueryChain.of(userBansMapper)
                .select(UserBans.class)
                .eq(UserBans::getUserId, userId)
                .orderBy(UserBans::getBanTime)
                .limit(1)
                .get();
    }

    /**
     * 获取用户分页列表（包含封禁信息）
     * <p>
     * 功能：
     * 1. 分页查询用户基本信息
     * 2. 查询并关联用户封禁信息
     * 3. 查询并关联封禁历史记录
     * <p>
     * 查询条件：
     * - 用户名（模糊匹配）
     * - 邮箱（模糊匹配）
     * - 用户状态（精确匹配）
     * <p>
     * 性能优化：
     * - 使用 QueryChain 进行高效查询
     * - 忽略空值条件
     * - 字符串自动去除首尾空格
     * <p>
     * 返回数据：
     * - 用户基本信息
     * - 当前封禁状态
     * - 剩余封禁时长
     * - 封禁原因
     * - 操作管理员
     * - 封禁历史记录
     *
     * @param queryDTO 查询条件，包含：
     *                 - username: 用户名（可选）
     *                 - email: 邮箱（可选）
     *                 - status: 用户状态（可选，0-正常，1-封禁）
     *                 - page: 页码
     *                 - pageSize: 每页大小
     * @return Page<UserPageVO> 分页结果，包含：
     * - total: 总记录数
     * - pages: 总页数
     * - records: 当前页数据列表
     */
    @Override
    public Pager<UserPageVO> getUsersPage(UserPageQueryDTO queryDTO) {
        // 构建查询链
        QueryChain<Users> queryChain = QueryChain.of(usersMapper)
                .ignoreNullValueInCondition(true)
                .ignoreEmptyInCondition(true)
                .trimStringInCondition(true);

        // 添加查询条件
        if (StringUtils.hasText(queryDTO.getUsername())) {
            queryChain.like(Users::getUsername, queryDTO.getUsername());
        }
        if (StringUtils.hasText(queryDTO.getEmail())) {
            queryChain.like(Users::getEmail, queryDTO.getEmail());
        }
        if (queryDTO.getStatus() != null) {
            queryChain.eq(Users::getStatus, queryDTO.getStatus());
        }

        // 添加排序条件：先按注册时间降序，再按最后登录时间降序
        queryChain.orderBy(Users::getRegistrationDate)
                .orderBy(Users::getLastLogin);

        // 执行分页查询
        Pager<Users> usersPager = queryChain.paging(Pager.of(queryDTO.getPage(), queryDTO.getPageSize()));

        // 创建结果Pager
        Pager<UserPageVO> resultPager = new Pager<>();
        resultPager.setNumber(queryDTO.getPage());
        resultPager.setSize(queryDTO.getPageSize());
        resultPager.setTotal(usersPager.getTotal());

        // 处理每条记录
        List<UserPageVO> voList = usersPager.getResults().stream().map(user -> {
            UserPageVO vo = new UserPageVO();
            // 手动拷贝属性，确保字段正确映射
            vo.setUserId(user.getUserId());
            vo.setUsername(user.getUsername());
            vo.setEmail(user.getEmail());
            vo.setCreateTime(user.getRegistrationDate());
            vo.setLastLoginTime(user.getLastLogin());
            vo.setStatus(user.getStatus());

            // 获取用户当前的封禁信息
            UserBanInfoVO banInfo = getCurrentBanInfo(user.getUserId());
            if (banInfo != null) {
                vo.setBanDuration(banInfo.getBanDuration());
                vo.setBanTimeLeft((int) StpUtil.getDisableTime(user.getUserId()));
                vo.setBanAdminName(banInfo.getBanAdminName());
                vo.setBanReason(banInfo.getBanReason());
            }

            // 获取封禁历史
            vo.setBanHistory(getUserBanHistory(user.getUserId()).stream()
                    .map(ban -> {
                        UserPageVO.BanHistoryVO historyVO = new UserPageVO.BanHistoryVO();
                        // 手动映射字段
                        historyVO.setBanTime(ban.getBanTime());
                        historyVO.setDuration(ban.getBanDuration());
                        historyVO.setAdminName(adminUserService.getAdminDetails(ban.getAdminId()).getUsername());
                        historyVO.setReason(ban.getBanReason());
                        historyVO.setStatus(user.getStatus());
                        return historyVO;
                    }).collect(Collectors.toList()));

            return vo;
        }).collect(Collectors.toList());

        resultPager.setResults(voList);
        return resultPager;
    }

} 